import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;

import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.AttachVolumeRequest;
import com.amazonaws.services.ec2.model.CreateSnapshotRequest;
import com.amazonaws.services.ec2.model.CreateSnapshotResult;
import com.amazonaws.services.ec2.model.CreateTagsRequest;
import com.amazonaws.services.ec2.model.CreateVolumeRequest;
import com.amazonaws.services.ec2.model.CreateVolumeResult;
import com.amazonaws.services.ec2.model.DescribeInstancesResult;
import com.amazonaws.services.ec2.model.DetachVolumeRequest;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.Reservation;
import com.amazonaws.services.ec2.model.RunInstancesRequest;
import com.amazonaws.services.ec2.model.RunInstancesResult;
import com.amazonaws.services.ec2.model.Snapshot;
import com.amazonaws.services.ec2.model.SpotInstanceRequest;
import com.amazonaws.services.ec2.model.StartInstancesRequest;
import com.amazonaws.services.ec2.model.StopInstancesRequest;
import com.amazonaws.services.ec2.model.Tag;
import com.amazonaws.services.ec2.model.TerminateInstancesRequest;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.S3Object;

import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.CreateImageRequest;
import com.amazonaws.services.ec2.model.CreateImageResult;

import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.TimeZone;

import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.cloudwatch.AmazonCloudWatchClient;
import com.amazonaws.services.cloudwatch.model.Datapoint;
import com.amazonaws.services.cloudwatch.model.Dimension;
import com.amazonaws.services.cloudwatch.model.GetMetricStatisticsRequest;
import com.amazonaws.services.cloudwatch.model.GetMetricStatisticsResult;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.AllocateAddressResult;
import com.amazonaws.services.ec2.model.AssociateAddressRequest;
import com.amazonaws.services.ec2.model.DisassociateAddressRequest;

public class HW2Final{
	static AmazonEC2      ec2;
    static AmazonS3Client s3;
	static AWSCredentials credentials;
	static String AMIid1 = "";
	static String AMIid2 = "";
	static String AMIid = null;
	static String instId1 = "";
	static String instId2 = "";
	
	public static void main(String [] args) throws Exception{
    	credentials = new PropertiesCredentials(
      			 HW2Final.class.getResourceAsStream("AwsCredentials.properties"));
    	
    	Boolean SignIn = true;
    	System.out.println("Sign In (Y/N)?");
    	Scanner sc = new Scanner(System.in);
    	String resp = sc.next();
    	if(resp == "n" || resp == "N")
    		SignIn = false;
    	
    	while(SignIn){	
    		
    			if(AMIid != null){
    				String[] AMI = AMIid.split(" ");
    				AMIid1 = AMI[0];
    				AMIid2 = AMI[1];
    			}
    	
    			else{
    				AMIid1 = "ami-e0a35789";
    				AMIid2 = "ami-e0a35789";
    			}
    	
    			String instId = createInstance(AMIid1, AMIid2);
    			String[] instIds = instId.split(" ");
    			String VolumeId = makePersistentVolumes(instIds[0],instIds[1]);
    			String[] volumes = VolumeId.split(" ");
    			makeS3(AMIid);
    			Thread.sleep(10000);
    			Double cpuUsage1 = monitorResources(instIds[0]);
    			Thread.sleep(10000);
    			Double cpuUsage2 = monitorResources(instIds[1]);
    			if(cpuUsage1 < 15.0)
    				AMIid = makeAMIForShutDown(instIds[0],volumes[0]);
    			if(cpuUsage2 < 15.0)
    				AMIid = makeAMIForShutDown(instIds[1],volumes[1]);
    			//int time = 9; 
    			for(int time = 9; time<=17;time++){
        			Thread.sleep(18);
        	    		if(time == 17){
        	    			AMIid1 = makeAMIForShutDown(instIds[0],volumes[0]);
        	    			AMIid1 = makeAMIForShutDown(instIds[1],volumes[1]);
        	    			AMIid = AMIid1+" "+AMIid2;
        	    		}	
 
    		}
    	}
	}
	
    public static String makePersistentVolumes(String instId1,String instId2)throws Exception{
    	
    	// Creating amazon client objects for each of the employees
    	
    	ec2 = new AmazonEC2Client(credentials);
    	String createdVolumeId1 = "";
    	String createdVolumeId2 = "";
        try{
        	CreateVolumeRequest cvr1 = new CreateVolumeRequest();
        	cvr1.setAvailabilityZone("us-east-1b");
        	cvr1.setSize(10); 		//size = 10 GigaBytes
        	CreateVolumeResult volumeResult1 = ec2.createVolume(cvr1);
        	createdVolumeId1 = volumeResult1.getVolume().getVolumeId();
     	
        	CreateVolumeRequest cvr2 = new CreateVolumeRequest();
        	cvr2.setAvailabilityZone("us-east-1b");
        	cvr2.setSize(10); 		//size = 10 GigaBytes
        	CreateVolumeResult volumeResult2 = ec2.createVolume(cvr2);
        	createdVolumeId2 = volumeResult2.getVolume().getVolumeId();
     	
    	// attaching the volume to both the employee instances
    	
        	AttachVolumeRequest avr1 = new AttachVolumeRequest();
        	avr1.setVolumeId(createdVolumeId1);
        	avr1.setInstanceId(instId1);
        	avr1.setDevice("/dev/sdf");
        	
        	ec2.attachVolume(avr1);
    	
        	AttachVolumeRequest avr2 = new AttachVolumeRequest();
        	avr2.setVolumeId(createdVolumeId2);
        	avr2.setInstanceId(instId2);
        	avr2.setDevice("/dev/sdf");
        	ec2.attachVolume(avr2);
        	
        	
    
        }
        catch(AmazonServiceException ase){
        	System.out.println("Caught Exception: " + ase.getMessage());
        	System.out.println("Reponse Status Code: " + ase.getStatusCode());
        	System.out.println("Error Code: " + ase.getErrorCode());
        	System.out.println("Request ID: " + ase.getRequestId());
        }
    
        String Volumes = createdVolumeId1+" "+createdVolumeId2; 
        return Volumes;
    }

    public static void makeS3(String AMIid)throws Exception{
  	try{
    	s3  = new AmazonS3Client(credentials);
        
        //create bucket
        	String bucketName = "cloud-sample-bucket-officegroup";
        	s3.createBucket(bucketName);
        
        //set key
        	String key = "AMIids.txt";
        
        //set value
        	File file = File.createTempFile("temp", ".txt");
        	file.deleteOnExit();
        	Writer writer = new OutputStreamWriter(new FileOutputStream(file));
        	//if(AMIid == null)
          	writer.write("added");
        	writer.close();
        
        //put object - bucket, key, value(file)
        	s3.putObject(new PutObjectRequest(bucketName, key, file));
        
        //get object
        	S3Object object = s3.getObject(new GetObjectRequest(bucketName, key));
        	BufferedReader reader = new BufferedReader(
        	    new InputStreamReader(object.getObjectContent()));
        	String data = null;
        	while ((data = reader.readLine()) != null) {
        		System.out.println("#Data in file in the clouud"+ data);
        	}
    
    
        }
        catch(AmazonServiceException ase){
        	System.out.println("Caught Exception: " + ase.getMessage());
        	System.out.println("Reponse Status Code: " + ase.getStatusCode());
        	System.out.println("Error Code: " + ase.getErrorCode());
        	System.out.println("Request ID: " + ase.getRequestId());
        }
    
    }

    public static String makeAMIForShutDown(String InstanceId, String volumeId) throws Exception{
    	 ec2 = new AmazonEC2Client(credentials);
    	 String imageAMIId = "";
    	 try{
 
    	// AMIs for both office instances created	 
 			DetachVolumeRequest dvr = new DetachVolumeRequest();
            dvr.setVolumeId(volumeId);
            dvr.setInstanceId(InstanceId);
            ec2.detachVolume(dvr);
            
            
        	//Snapshot the Volume
            CreateSnapshotRequest csr = new CreateSnapshotRequest();
            csr.setVolumeId(volumeId);
            CreateSnapshotResult csr1 = ec2.createSnapshot(csr);
            Snapshot ss = csr1.getSnapshot();
            String snapshotId = ss.getSnapshotId();
        	//Do we need to detete the volume? If yes, then recreate the volume from the snapshot when restarting the instance!
        	
    		CreateImageRequest cir1 = new CreateImageRequest();
 			cir1.setInstanceId(InstanceId);
 			cir1.setName(InstanceId);
 			CreateImageResult createImageResult1 = ec2.createImage(cir1);
 			String createdImageId1 = createImageResult1.getImageId();
        	imageAMIId += createdImageId1+" "; 
 			System.out.println("Sent creating AMI request. AMI id="+createdImageId1);	

    		List<String> instanceIds = new LinkedList<String>();
    		instanceIds.add(InstanceId);
          
 			TerminateInstancesRequest tir = new TerminateInstancesRequest(instanceIds);
 			tir.withInstanceIds(instanceIds);
 		
    	 } catch (AmazonServiceException ase) {
                System.out.println("Caught Exception: " + ase.getMessage());
                System.out.println("Reponse Status Code: " + ase.getStatusCode());
                System.out.println("Error Code: " + ase.getErrorCode());
                System.out.println("Request ID: " + ase.getRequestId());
        }

    	 return imageAMIId;
    }

    public static Double monitorResources(String instanceId) throws Exception {
    	ec2 = new AmazonEC2Client(credentials);
    	Double averageCPU1 = null;
		try{
			// Allocating elastic IP addresses to each resource for monitoring
			AllocateAddressResult elasticResult1 = ec2.allocateAddress();
			String elasticIp1 = elasticResult1.getPublicIp();
			System.out.println("New elastic IPcf1: "+elasticIp1);
			
			// Associating IP to each machine
			AssociateAddressRequest aar1 = new AssociateAddressRequest();
			aar1.setInstanceId(instanceId);
			aar1.setPublicIp(elasticIp1);
			ec2.associateAddress(aar1);
			
			// Creating CloudWatch Client for monitoring//
			
			AmazonCloudWatchClient cloudWatch1 = new AmazonCloudWatchClient(credentials) ;
			
			//create request message
			GetMetricStatisticsRequest statRequest1 = new GetMetricStatisticsRequest();
			
			//set up request message
			statRequest1.setNamespace("AWS/EC2"); //namespace
			statRequest1.setPeriod(60); //period of data
			ArrayList<String> stats1 = new ArrayList<String>();
			
			//Use one of these strings: Average, Maximum, Minimum, SampleCount, Sum 
			stats1.add("Average"); 
			stats1.add("Sum");
			statRequest1.setStatistics(stats1);
			
			//Use one of these strings: CPUUtilization, NetworkIn, NetworkOut, DiskReadBytes, DiskWriteBytes, DiskReadOperations  
			statRequest1.setMetricName("CPUUtilization"); 
			
			// set time
			GregorianCalendar calendar1 = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
			calendar1.add(GregorianCalendar.SECOND, -1 * calendar1.get(GregorianCalendar.SECOND)); // 1 second ago
			Date endTime1 = calendar1.getTime();
			calendar1.add(GregorianCalendar.MINUTE, -10); // 10 minutes ago
			Date startTime1 = calendar1.getTime();
			statRequest1.setStartTime(startTime1);
			statRequest1.setEndTime(endTime1);
			
			//specify an instance
			ArrayList<Dimension> dimensions = new ArrayList<Dimension>();
			dimensions.add(new Dimension().withName("InstanceId1").withValue(instanceId));
			statRequest1.setDimensions(dimensions);
			
			//get statistics
			GetMetricStatisticsResult statResult1 = cloudWatch1.getMetricStatistics(statRequest1);
			
			//display
			System.out.println(statResult1.toString());
			List<Datapoint> dataList = statResult1.getDatapoints();
			
			Date timeStamp1 = null;
			for (Datapoint data : dataList){
				averageCPU1 = data.getAverage();
				timeStamp1 = data.getTimestamp();
				System.out.println("Average CPU utlilization for last 10 minutes: "+averageCPU1);
				System.out.println("Totl CPU utlilization for last 10 minutes: "+data.getSum());
			}
		
		
		}
	
		 catch (AmazonServiceException ase) {
			    System.out.println("Caught Exception: " + ase.getMessage());
			    System.out.println("Reponse Status Code: " + ase.getStatusCode());
			    System.out.println("Error Code: " + ase.getErrorCode());
			    System.out.println("Request ID: " + ase.getRequestId());
		 }
		return averageCPU1;
    }

    public static String createInstance(String AMIid1, String AMIid2)throws Exception{

 
    	String createdInstanceId = null;
    	ec2 = new AmazonEC2Client(credentials);
    	try{
    		
    		String imageId1 = AMIid1; //SUSE 32-bit Amazon AMI
    		String imageId2 = AMIid2; 
    		int minInstanceCount = 2; // create 1 instance
    		int maxInstanceCount = 2;
    		RunInstancesRequest rir1 = new RunInstancesRequest(imageId1, minInstanceCount, maxInstanceCount);
    		
         
    		RunInstancesResult result1 = ec2.runInstances(rir1);
    		List<Instance> resultInstance1 = result1.getReservation().getInstances();
    		
    		createdInstanceId = "";
    		
    		for (Instance ins : resultInstance1){
    			createdInstanceId += ins.getInstanceId()+" ";
          
    			System.out.println("New instance has been created: "+ins.getInstanceId());
    		}
    		
    		Thread.sleep(60000);
    		List<String> resources = new LinkedList<String>();
    		List<Tag> tags = new LinkedList<Tag>();
    		Tag nameTag = new Tag("Name", "MyFirstInstance");
          
    		resources.add(createdInstanceId);
    		tags.add(nameTag);
          
    		CreateTagsRequest ctr = new CreateTagsRequest(resources, tags);
    		
          
    
    		List<String> instanceIds = new LinkedList<String>();
    		instanceIds.add(createdInstanceId);
          
          //stop
    		StopInstancesRequest stopIR = new StopInstancesRequest(instanceIds);
    		StartInstancesRequest startIR = new StartInstancesRequest(instanceIds);
          
    		String desc = ec2.describeInstances().toString();
    		System.out.println("instance description" + desc);
    
    		TerminateInstancesRequest tir = new TerminateInstancesRequest(instanceIds);
    		
      } 
    catch (AmazonServiceException ase) {
              System.out.println("Caught Exception: " + ase.getMessage());
              System.out.println("Reponse Status Code: " + ase.getStatusCode());
              System.out.println("Error Code: " + ase.getErrorCode());
              System.out.println("Request ID: " + ase.getRequestId());
      }

    	return createdInstanceId;
    }

 
}

	